package com.java.concurrent.server;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class MiniProgramGenerator {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        List<Map<String, Object>> components = mapper.readValue(
                new File("D:\\download\\google\\data.json"), new TypeReference<List<Map<String, Object>>>() {});

        Map<String, Object> rectStyle = null;
        String rectClassName = null;
        for (Map<String, Object> comp : components) {
            if ("RectShape".equals(comp.get("component"))) {
                rectStyle = (Map<String, Object>) comp.get("style");
                rectClassName = (String) comp.get("id");
                break;
            }
        }

        if (rectStyle == null) {
            System.out.println("未找到 RectShape 元素");
            return;
        }

        double baseLeft = toDouble(rectStyle.get("left"));
        double baseTop = toDouble(rectStyle.get("top"));
        double baseWidth = toDouble(rectStyle.get("width"));
        double baseHeight = toDouble(rectStyle.get("height"));
        double scale = baseHeight / baseWidth;

        StringBuilder wxml = new StringBuilder("<view class=\"container\">\n");
        wxml.append("  <view class=\"").append(rectClassName).append("\">\n");
        StringBuilder wxss = new StringBuilder(".container {\n width: 100%;\n padding-top:30%\n}\n\n");
        StringBuilder js = new StringBuilder();

        int zIndex = 1;

        for (Map<String, Object> component : components) {
            String id = (String) component.get("id");
            String type = (String) component.get("component");
            Object propValue = component.get("propValue");
            Map<String, Object> style = (Map<String, Object>) component.get("style");

            String className = id;

            // 生成WXML
            switch (type) {
                case "Picture":
                case "CircleShape":
                    Map<String, Object> pvMap = propValue instanceof Map ? (Map<String, Object>) propValue : new HashMap<>();
                    String imageUrl = String.valueOf(pvMap.getOrDefault("url", ""));

                    wxml.append("  <view class=\"").append(className)
                    .append("\" bindtap=\"onChooseImage").append(id).append("\">\n")
                    .append("    <image src=\"{{ img").append(id).append(" || '").append(imageUrl)
                    .append("' }}\" mode=\"aspectFill\" class=\"")
                    .append(className).append("-img\"/>\n")
                    .append("  </view>\n");
                
                    wxml.append("  <simple-crop\n")
                        .append("    wx:if=\"{{ showCropper").append(id).append(" }}\"\n")
                        .append("    id=\"cropper").append(id).append("\"\n")
                        .append("    src=\"{{ cropSrc").append(id).append(" }}\"\n")
                        .append("    size=\"{{ cropSize").append(id).append(" }}\"\n")
                        .append("    bind:ready=\"onCropperReady").append(id).append("\"\n")
                        .append("    bindcropClose=\"onCropClose").append(id).append("\"\n")
                        .append("    bindcropCrop=\"onCropFinish").append(id).append("\"\n")
                        .append("  ></simple-crop>\n");
                
                

                        js.append("  onChooseImage").append(id).append("() {\n")
                        .append("    wx.chooseImage({\n")
                        .append("      count: 1,\n")
                        .append("      sizeType: ['original'],\n")
                        .append("      sourceType: ['album', 'camera'],\n")
                        .append("      success: (res) => {\n")
                        .append("        const path = res.tempFilePaths[0];\n")
                        .append("        wx.getImageInfo({\n")
                        .append("          src: path,\n")
                        .append("          success: info => {\n")
                        .append("            const shorter = Math.min(info.width, info.height);\n")
                        .append("            const size = Math.floor(shorter * 0.8);\n")
                        .append("            this.setData({\n")
                        .append("              cropSrc").append(id).append(": path,\n")
                        .append("              cropSize").append(id).append(": { width: size, height: size },\n")
                        .append("              showCropper").append(id).append(": true\n")
                        .append("            });\n")
                        .append("          }\n")
                        .append("        });\n")
                        .append("      }\n")
                        .append("    });\n")
                        .append("  },\n");
                      
                      js.append("  onCropperReady").append(id).append("() {\n")
                        .append("    this.cropper").append(id).append(" = this.selectComponent('#cropper").append(id).append("');\n")
                        .append("  },\n");
                      
                      js.append("  onCropClose").append(id).append("() {\n")
                        .append("    this.setData({ showCropper").append(id).append(": false });\n")
                        .append("  },\n");
                      
                      js.append("  onCropFinish").append(id).append("(e) {\n")
                        .append("    const croppedPath = e.detail.resultSrc;\n")
                        .append("    this.setData({\n")
                        .append("      img").append(id).append(": croppedPath,\n")
                        .append("      showCropper").append(id).append(": false\n")
                        .append("    });\n")
                        .append("  },\n");
                      

                    wxss.append(".").append(className).append("-img {\n")
                            .append("  width: 100%;\n  height: 100%;\n  object-fit: cover;\n}\n\n");
                    break;
                case "VText":
                    wxml.append("  <view class=\"").append(className).append("\">\n")
                    .append("    <textarea class=\"").append(className).append("-input\" ")
                    .append("value=\"{{ ").append("input").append(id).append(" || '").append(propValue).append("' }}\" ")
                    .append("bindinput=\"onInputChange").append(id).append("\" ")
                    .append("auto-height=\"true\" />\n")
                    .append("  </view>\n");
            
                
                
                    wxss.append(".").append(className).append("-input {\n")
                        .append("  width: 100%;\n")
                        .append("  height: 100%;\n")
                        .append("  border: none;\n")
                        .append("  background: transparent;\n")
                        .append("  font-size: inherit;\n")
                        .append("  color: inherit;\n")
                        .append("  padding: 0;\n")
                        .append("  margin: 0;\n")
                        .append("}\n\n");
                    break;
                
                case "RectShape":
                    // 矩形内可能还有内容，暂时不处理
                    break;
                default:
                    // 其他类型组件可扩展
                    break;
            }

            // 计算百分比定位
            double left = toDouble(style.get("left"));
            double top = toDouble(style.get("top"));
            double width = toDouble(style.get("width"));
            double height = toDouble(style.get("height"));

            double leftPercent = (left - baseLeft) / baseWidth * 100;
            double topPercent = (top - baseTop) / baseHeight * 100 * scale;
            double widthPercent = width / baseWidth * 100;
            double heightPercent = height / baseHeight * 100 * scale;

            // 生成CSS样式
            CssBuilder cssBuilder = new CssBuilder(className);
            cssBuilder.addRule("left", String.format("%.2f%%", leftPercent));
            cssBuilder.addRule("top", String.format("%.2fvw", topPercent));
            cssBuilder.addRule("width", String.format("%.2f%%", widthPercent));
            cssBuilder.addRule("height", String.format("%.2fvw", heightPercent));

            // 组件特殊样式
            switch (type) {
                case "CircleShape":
                    cssBuilder.addRule("border-radius", "50%");
                    cssBuilder.addRule("overflow", "hidden");
                    cssBuilder.addRule("display", "flex");
                    cssBuilder.addRule("justify-content", "center");
                    cssBuilder.addRule("align-items", "center");
                    cssBuilder.addRule("position", "absolute");
                    break;
                case "RectShape":
                    cssBuilder.addRule("position", "relative");
                    cssBuilder.addRule("z-index", "0");
                    break;
                default:
                    cssBuilder.addRule("position", "absolute");
                    cssBuilder.addRule("z-index", String.valueOf(zIndex));
                    break;
            }

            // 统一遍历 style 生成CSS，跳过已写入的定位和尺寸属性
            Set<String> skipKeys = Set.of("width", "height", "top", "left");
            for (Map.Entry<String, Object> entry : style.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if (value == null || value.toString().isEmpty()) continue;
                if (skipKeys.contains(key)) continue;
            
                String cssKey = camelToKebabCase(key);
                String cssValue = value.toString();
            
                if ("rotate".equals(key)) {
                    cssBuilder.addRule("transform", "rotate(" + cssValue + "deg)");
                    continue;
                }
            
                if ("opacity".equals(key)) {
                    try {
                        cssValue = String.format("%.1f", Double.parseDouble(cssValue));
                    } catch (Exception ignored) {}
                }
            
                // ⚠️ 添加 fontSize 缩放支持
                if ("fontSize".equals(key)) {
                    double rawFontSize = toDouble(value);
                    double fontScale = rawFontSize / baseWidth * 100;
                    cssBuilder.addRule("font-size", String.format("%.2fvw", fontScale));
                    continue;
                }
            
                // 其他单位的判断与添加
                if (isCssNumberProperty(cssKey)) {
                    cssValue = appendUnitIfNeeded(cssValue, "rpx");
                }
            
                cssBuilder.addRule(cssKey, cssValue);
            }
            

            wxss.append(cssBuilder.build()).append("\n");
            zIndex++;
        }

        wxml.append("</view></view>\n");

        // 矩形容器样式（宽度100%，高度等比）
        wxss.append(".").append(rectClassName).append(" {\n")
                .append("  width: 100%;\n")
                .append("  height: ").append(String.format("%.2fvw", scale * 100)).append(";\n")
                .append("  position: relative;\n")
                .append("}\n");

        String jsPage = "Page({\n" + js.toString() + "})";

        System.out.println("=== WXML ===");
        System.out.println(wxml.toString());
        System.out.println("\n=== WXSS ===");
        System.out.println(wxss.toString());
        System.out.println("\n=== JS ===");
        System.out.println(jsPage);
    }

    // 简单判断哪些CSS属性通常是带数字单位的
    private static boolean isCssNumberProperty(String cssKey) {
        return cssKey.endsWith("width")
                || cssKey.endsWith("height")
                || cssKey.endsWith("size")
                || cssKey.endsWith("spacing")
                || cssKey.endsWith("radius")
                || cssKey.equals("padding")
                || cssKey.equals("margin")
                || cssKey.equals("font-weight")
                || cssKey.equals("letter-spacing")
                || cssKey.equals("line-height");
    }

    private static String appendUnitIfNeeded(String value, String unit) {
        // 如果值本身含有单位，直接返回
        if (value.matches(".*\\d+.*(px|rpx|em|rem|%)$")) {
            return value;
        }
        // 否则添加单位
        if (value.matches("^-?\\d+(\\.\\d+)?$")) {
            return value + unit;
        }
        return value;
    }

    private static double toDouble(Object value) {
        if (value == null) return 0;
        if (value instanceof Number) return ((Number) value).doubleValue();
        try {
            return Double.parseDouble(value.toString());
        } catch (Exception e) {
            return 0;
        }
    }

    private static String camelToKebabCase(String str) {
        return str.replaceAll("([a-z])([A-Z]+)", "$1-$2").toLowerCase();
    }

    private static String getComponentIdByType(List<Map<String, Object>> components, String type) {
        for (Map<String, Object> comp : components) {
            if (type.equals(comp.get("component"))) {
                return (String) comp.get("id");
            }
        }
        return "unknown";
    }

    // CSS构造辅助类
    private static class CssBuilder {
        private final String className;
        private final StringBuilder builder = new StringBuilder();

        public CssBuilder(String className) {
            this.className = className;
            builder.append(".").append(className).append(" {\n");
        }

        public void addRule(String property, String value) {
            builder.append("  ").append(property).append(": ").append(value).append(";\n");
        }

        public String build() {
            builder.append("}\n");
            return builder.toString();
        }
    }
}
